#!coding:utf-8
# vim: tabstop=4 shiftwidth=4 softtabstop=4

import base64
import json

from django.db import transaction
from django.db.models import Q, Sum
from djcelery.models import PeriodicTask, CrontabSchedule
from eventlet.green import time
from rest_framework import mixins, status
from rest_framework.generics import SingleObjectAPIView
from rest_framework.response import Response
from cvirt.manager.views import NonModelBaseAPIView, BaseListAPIView, NamedAPIViewMixIn, BaseRetriveAPIView
from cvirt.manager.models import Cluster, Server, Instance, Storage, Network,\
    Event, Datacenter, SecurityGroup
from cvirt.manager.serializers import EventSerializer, VMSerializer,\
    StorageSerializer, NetworkSerializer,VM_no_relation_serializer, SecurityGroupSerializer
from cvirt.manager.serializers import HostSerializer
from cvirt.manager.serializers import DatacenterSerializer
# from cvirt.manager.models import CvirtPeriodicTask
from cvirt.manager.serializers import PeriodicTaskSerializer


class DatacenterView(NamedAPIViewMixIn,BaseListAPIView):
    model = Datacenter
    serializer_class = DatacenterSerializer

    def _get(self,request,*args,**kwargs):
        return self.list(request,*args,**kwargs)

    def create(self, request, *args, **kwargs):
        name = request.DATA.get('name')
        if name:
            datacenter = Datacenter.objects.create(name=name)
            return Response(self.get_serializer(datacenter).data)
        return Response("name can not be null", status=status.HTTP_400_BAD_REQUEST)

    def q(self,req,*args,**kwargs):
        term = self.get_query_string("term")
        result = []
        if term:
            for c in Cluster.objects.filter(name__regex=term):
                result.append(dict(label=c.name,value=c.name,
                                   url="#/cluster/%s"% c.id,icon="/static/images/cluster.png"))
            for s in Server.objects.filter(host_name__regex=term):
                result.append(dict(label=s.host_name,value=s.host_name,
                                   url="#/host/%s"% s.id,icon="/static/images/host.png"))
            for vm in Instance.objects.filter(name__regex=term):
                result.append(dict(label=vm.name,value=vm.name,
                                   url="#/vm/%s"% vm.id,icon="/static/images/vmstatus/%s.png" % vm.status.lower()))

        return Response(result)

class DatacenterDetail(NamedAPIViewMixIn,mixins.RetrieveModelMixin,
                                   SingleObjectAPIView):
    #TODO 这里的方法不应该在datacenter中，后续再进一步重构
    model = Datacenter
    serializer_class = DatacenterSerializer
    def _get(self,request,*args,**kwargs):

        result =  self.retrieve(request,*args,**kwargs)
        servertotal = Server.objects.aggregate(cpunum=Sum('cpu'),memnum=Sum('mem'))
        storagetotal = Storage.objects.exclude(type='iso').aggregate(storage=Sum('totalsize'))
        usedstorage = Storage.objects.exclude(type='iso').aggregate(storage=Sum('used'))
        result.data.update(dict(totalcpu=servertotal['cpunum'],totalmem=servertotal['memnum'],
                                totalstorage=storagetotal['storage'],usedstorage=usedstorage['storage']))
        return result

    def create(self,request,*args,**kwargs):
        pass

    def hosts(self,request,*args,**kwargs):
        servers = Server.objects.filter(Q(cluster__datacenter__id=self.pk)|Q(cluster__isnull=True))
        data = self.paginate(request,servers,HostSerializer)
        #将主机的密码使用base64进行加密，增加主机的username属性并使用base64进行加密，便于和web ssh进行参数传递
        for server in data.get('data'):
            server['password'] = base64.b64encode(server.get('password'))
            server['username'] = base64.b64encode("root")
        return Response(data)

    def vms(self,request,*args,**kwargs):
        vms = Instance.objects.filter(host__cluster__datacenter__id=self.pk)
        data = self.paginate(request,vms,VMSerializer)
        # for iface in data['interface_set']:
        #     iface.securitygroups = [SecurityGroupSerializer(SecurityGroup.objects.get_or_none(pk=s)).data for s in iface.securitygroups ]
        return Response(data)

    def networks(self,request,*args,**kwargs):
        networks = Network.objects.all()
        data = self.paginate(request,networks,NetworkSerializer)
        return Response(data)

    def storages(self,request,*args,**kwargs):
        storages = Storage.objects.order_by('-type')
        data = self.paginate(request,storages,StorageSerializer)
        return Response(data)

    def tasks(self, request, *args, **kwargs):
        periodic_tasks = PeriodicTask.objects.all().exclude(name='celery.backend_cleanup')
        data = self.paginate(request, periodic_tasks, PeriodicTaskSerializer)
        return Response(data)

    def schedule_tasks(self, request, *args, **kwargs):
        #TODO:get schedule tasks dynamic, now use the configure way.
        # schedule_tasks = [{'name':'insert_task_data', 'value': 'cvirt.tasks.test_task.insert_task_data'}]
        schedule_tasks = [{'name':u'关机', 'value':'shutdown_vm'},
                          # {'name':u'创建', 'value':'create_vm'},
                          {'name':u'开机', 'value':'start_vm'},
                          {'name':u'重启', 'value':'reboot_vm'},
                          {'name':u'快照', 'value':'snapshot_vm'},
                          {'name':u'快照还原', 'value':'snapshot_restore'},
                          {'name':u'删除', 'value':'delete_vm'}]
        return Response({'data': schedule_tasks})

    def backups(self, request, *args, **kwargs):
        pass

    def add_schedule_task(self, request, *args, **kwargs):
        try:
            task = request.DATA.get('task')
            task_name = task.get('title')
            p = PeriodicTask.objects.filter(name=task_name)
            if p:
                return Response({"status": 400, "msg": "任务名称已存在."})

            vm = task.get('vm')
            if vm:
                task['queue'] = vm.get('host').get('host_name')
                task['kwargs'] = {'instid': vm.get('id'), 'task_name': task['task'].get('value')}
            else:
                if task['task'].get('value') != 'cvirt.tasks.create_vm':
                    return Response({"status": 400, "msg": "请至少选择一个虚拟机"})
            if task.get('snapshotname', None):
                task['kwargs'].update({"snapshotname": task['snapshotname']})
            if task.get('snapshot', None):
                task['kwargs'].update({"snapshotid": task['snapshot'].id})

            _task = self._add_task(task)
            data = {"id": _task.id, "name": _task.name, "desc":task['description'], 'start': task['start'], 'task': _task.task, 'kwargs':_task.kwargs,'queue': _task.queue}
            return Response({"status": 200, "data": data})
        except Exception as e:
            print 'exception is:', e
            return Response({"status": 500, "msg": "创建任务失败"})

    @transaction.commit_on_success
    def _add_task(self, task):
        start = task.get('start')
        expires_s = start
        starttime = start.split()[1]
        start = start.split()[0]

        minute = starttime.split(':')[1]
        hour = int(starttime.split(':')[0]) - 8
        day = start.split('-')[2]
        month = start.split('-')[1]

        kwargs = json.dumps(task.get('kwargs'))
        desc = '%s##%s' % (expires_s, task['description'])
        crontab = CrontabSchedule.objects.create(minute=minute, hour=hour, day_of_month=day, month_of_year=month)
        task = PeriodicTask.objects.create(crontab=crontab, name=task['title'], task='cvirt.tasks.schedule_task_broker',
                         kwargs=kwargs, description=desc, queue=task['queue'])
        return task

    def update_schedule_task(self, request, *args, **kwargs):
        try:
            task = request.DATA.get('task')
            newtask = self._update_task(task)
            return Response({'status': 200, 'newid':newtask.id, 'kwargs':newtask.kwargs})
        except Exception as e:
            print 'exception is:', e
            return Response({"status": 500})

    @transaction.commit_on_success
    def _update_task(self, params):
        #TODO:to only update the dirty data in angularJs
        task = PeriodicTask.objects.get(pk=params.get('id'))
        if params.get('start2', None):
            start = params.get('start2')
        else:
            start = params.get('start')

        expires_s = start
        starttime = start.split()[1]
        start = start.split()[0]
        if not params.get('dropevent', None):
            name = params.get('title')
            description = params.get('description')
            queue = params.get('vm').get('host').get('host_name')
            kwargs = {"instid": params.get('vm').get('id'), "task_name": params.get('task').get('value')}
            if params.get('snapshotname', None):
                kwargs.update({"snapshotname": params['snapshotname']})
            if params.get('snapshot', None):
                kwargs.update({"snapshotid": params['snapshot'].id})
            kwargs = json.dumps(kwargs)
            description = '%s##%s' % (expires_s, description)
        else:
            name = task.name
            description = task.description
            desc = description.split('##')[1] if description else ''
            queue = task.queue
            kwargs = task.kwargs
            description = '%s##%s' % (expires_s, desc)

        minute = starttime.split(':')[1]
        hour = int(starttime.split(':')[0]) - 8
        day = start.split('-')[2]
        month = start.split('-')[1]
        #TODO: confirm the correct usage.
        crontab = task.crontab
        crontab.minute = minute
        crontab.hour = hour
        crontab.day_of_month = day
        crontab.month_of_year = month
        crontab.save()
        #为了使celerybeat能够生效，先删除再新增
        task.delete()
        newtask = PeriodicTask.objects.create(crontab=crontab, name=name, task="cvirt.tasks.schedule_task_broker", kwargs=kwargs, description=description, queue=queue)
        return newtask

    def delete_schedule_task(self,request,*args,**kwargs):
        print request.DATA
        taskid = request.DATA.get('taskid')
        p = PeriodicTask.objects.filter(id=taskid)
        if p:
            p = p[0]
            crontab = p.crontab
            p.delete()
            crontab.delete()
            return Response({"status": 200, "msg": "ok"})
        else:
            return Response({"status": 500, "msg": "task not exists."})

    """数据中心负载前5主机"""
    def top_hosts(self,request,*args,**kwargs):
        num = self.get_query_string('n')
        num = num if num else 5
        #过滤未激活主机
        servers = Server.objects.filter(cluster__isnull=False,status=2).order_by('-cpu_usage','-mem_usage')[:num]
        return Response(HostSerializer(servers,many=True).data)

    def top_vms(self,request,*args,**kwargs):
        num = self.get_query_string('n')
        num = num if num else 5
        insts = Instance.objects.filter(status='running').order_by('-cpu_usage','-mem_usage')[:num]
        return Response(VM_no_relation_serializer(insts,many=True).data)

    def events(self,request,*args,**kwargs):
        events = Event.objects.all()
        data = self.paginate(request,events,EventSerializer)
        return Response(data)


class EventListView(NamedAPIViewMixIn, BaseRetriveAPIView):
    model = Event
    serializer_class = EventSerializer

    def _get(self, request, *args, **kwargs):

        dataset = Event.objects.all()
        result = self.paginate(request, dataset, EventSerializer)
        return Response(result)

    def delete_all(self, request, *args, **kwargs):
        ids = request.DATA.get('ids')
        for id in ids:
            Event.objects.filter(id=id).delete()

        return self._get(request, args, kwargs)
